﻿namespace BullsEyeGame
{
    internal class GuessResult
    {
        private const bool k_Match = true;
        private const bool k_Miss = true;

        private Guess m_Guess;
        private int m_NumberOfV = 0;
        private int m_NumberOfX = 0;

        private GuessResult(Guess i_NewGuess)
        {            
            m_Guess = i_NewGuess;
            calculateMatchMissValues();
        }
        
        public static GuessResult CreateGuessResult(Guess i_NewGuess)
        {
            GuessResult newGuessResult = null;

            if ((i_NewGuess != null) && (GameLogics.Instance.TargetGuess != null))
            {
                newGuessResult = new GuessResult(i_NewGuess);
            }

            return newGuessResult;
        }

        private void calculateMatchMissValues()
        {
            bool[] matchArray = new bool[Guess.k_GuessLength];

            m_NumberOfV = 0;
            m_NumberOfX = 0;            

            calculateMatchValues(matchArray);
            calculateMissValues(matchArray);
        }

        private void calculateMatchValues(bool[] o_MatchArray)
        {
            char currentGuessChar;
            char currentTargetChar;
            Guess targetGuess = GameLogics.Instance.TargetGuess;

            initializedFalseArray(o_MatchArray);
            for (int i = 0; i < Guess.k_GuessLength; ++i)
            {
                currentGuessChar = m_Guess.At(i);
                currentTargetChar = targetGuess.At(i);
                if (currentGuessChar == currentTargetChar)
                {
                    m_NumberOfV++;
                    o_MatchArray[i] = k_Match;
                }
            }

        }

        private void calculateMissValues(bool[] i_MatchArray)
        {       
            bool[] missArray = new bool[Guess.k_GuessLength];
            char currentGuessChar;
            Guess targetGuess = GameLogics.Instance.TargetGuess;
            bool keepChecking;            
            int? currentGuessCharTargetIndex;

            initializedFalseArray(missArray);
            for (int i = 0; i < Guess.k_GuessLength; ++i)
            {
                if (i_MatchArray[i] == k_Match)
                {
                    continue;
                }

                currentGuessCharTargetIndex = 0;
                keepChecking = true;
                currentGuessChar = m_Guess.At(i);
                while (currentGuessCharTargetIndex < Guess.k_GuessLength && keepChecking)
                {                    
                    currentGuessCharTargetIndex = targetGuess.IndexOf(currentGuessChar, (int)currentGuessCharTargetIndex);
                    keepChecking = currentGuessCharTargetIndex == Guess.k_CharNotFound || currentGuessCharTargetIndex == null; 
                    if (!keepChecking)
                    {
                        keepChecking = missArray[(int)currentGuessCharTargetIndex] == k_Miss;
                        keepChecking |= i_MatchArray[(int)currentGuessCharTargetIndex] == k_Match;
                        if (keepChecking)
                        {                            
                            currentGuessCharTargetIndex++;
                        }
                        else
                        {
                            m_NumberOfX++;
                            missArray[(int)currentGuessCharTargetIndex] = k_Miss;
                        }
                    } 
                }
            }
        }

        private void initializedFalseArray(bool[] o_Array)
        {
            for (int i = 0; i < o_Array.Length; ++i)
            {
                o_Array[i] = false;
            }

        }

        public bool isMatch()
        {            
            return m_NumberOfV == Guess.k_GuessLength;
        }

        public int NumberOfV
        {
            get { return m_NumberOfV; }
            set { m_NumberOfV = value; }
        }

        public int NumberOfX
        {
            get { return m_NumberOfX; }
            set { m_NumberOfX = value; }
        }

        public Guess Guess
        {
            get { return m_Guess; }
        }
    }
}
